﻿using System;
using System.IO;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Threading;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Xml.Linq;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

using XmlVisualizer.Models;
using XmlVisualizer.Controllers;
using XmlVisualizer.DiagramDesigner;


namespace XmlVisualizer.Models {
	/// <summary>
	/// Information about XNode for visual reasons.
	/// </summary>
	public class XNodeInfo {
		#region Constructors
		/// <summary>
		/// Initializes a new instance of the XNodeInfo class.
		/// </summary>
		/// <param name="position">XNode's position.</param>
		/// <param name="depth">XNode's depth.</param>
		/// <param name="order">XNode's order.</param>
		/// <param name="node">Reference to XNode</param>
		/// <exception cref="System.ArgumentNullException">node is null.</exception>
		public XNodeInfo(Point position, int depth, int order, string appearanceTemplate, XNode node) : this(position, depth, order, appearanceTemplate) {
			if (node == null)
				throw new ArgumentNullException("node");
			this.node = node;
		}

		public XNodeInfo(Point position, int depth, int order, string appearanceTemplate) {
			Position = position;
			Depth = depth;
			Order = order;
			AppearanceTemplate = appearanceTemplate;
		}

		#endregion

		#region Properties
		public ElementAddress ElementInfo { get; set; }

		/// <summary>
		/// Gets or sets the position.
		/// </summary>
		public Point Position { get; set; }

		/// <summary>
		/// Gets or sets the depth.
		/// </summary>
		public int Depth { get; set; }

		/// <summary>
		/// Gets or sets the order.
		/// </summary>
		public int Order { get; set; }

		private XNode node;
		/// <summary>
		/// Gets or set the XNode.
		/// </summary>
		public XNode Node {
			get { return node; }
			set { node = value; }
		}

		private Control ui;
		/// <summary>
		/// Gets or sets the DesignerItem.
		/// </summary>
		public Control UI {
			get { return ui; }
			set { ui = value; }
		}

		private String appearanceTemplate;
		public String AppearanceTemplate {
			get { return appearanceTemplate; }
			set { appearanceTemplate = value; }
		}

		public Guid ID { get; set; }
		#endregion

		#region Methods
		/// <summary>
		/// Serializes XNodeInfo into Xml.
		/// </summary>
		/// <returns>XElement with serialized XNodeInfo.</returns>
		public XElement Serialize() {
			XElement root = new XElement("XNodeInfo");
			root.Add(new XElement("Position", Position));
			root.Add(new XElement("Depth", Depth));
			root.Add(new XElement("Order", Order));
			root.Add(new XElement("AppearanceTemplate", AppearanceTemplate));
			root.Add(new XElement("ID", ID));

			return root;
		}

		/// <summary>
		/// Deserializes XNodeInfo from xml.
		/// </summary>
		/// <param name="root">root element with serialized XNodeInfo.</param>
		/// <returns>deserialized XNodeInfo</returns>
		/// <exception cref="System.IO.FileFormatException">file is corrupted</exception>
		public static XNodeInfo Deserialize(XElement root) {
			string s_position = root.Element("Position").Value;
			if (String.IsNullOrEmpty(s_position))
				throw new FileFormatException("Position is empty.");
			string s_depth = root.Element("Depth").Value;
			if (String.IsNullOrEmpty(s_depth))
				throw new FileFormatException("Depth is empty.");
			string s_order = root.Element("Order").Value;
			if (String.IsNullOrEmpty(s_order))
				throw new FileFormatException("Order is empty.");
			string s_appearanceTemplate = root.Element("AppearanceTemplate").Value;
			if (String.IsNullOrEmpty(s_appearanceTemplate))
				throw new FileFormatException("AppearanceTemplate is empty.");
			string s_guid = root.Element("ID").Value;
			if (String.IsNullOrEmpty(s_guid))
				throw new FileFormatException("ID is empty.");

			try {
				Point position = Point.Parse(s_position);
				int depth = int.Parse(s_depth);
				int order = int.Parse(s_order);
				Guid id = new Guid(s_guid);

				XNodeInfo info = new XNodeInfo(position, depth, order, s_appearanceTemplate);
				info.ID = id;
				return info;
			} catch (FormatException ex) {
				throw new FileFormatException("File is corrupted.", ex);
			} catch (InvalidOperationException ex) {
				throw new FileFormatException("File is corrupted.", ex);
			} catch (OverflowException ex) {
				throw new FileFormatException("File is corrupted.", ex);
			} catch (ArgumentNullException ex) {
				throw new FileFormatException("File is corrupted.", ex);
			}
		}
		#endregion
	}

	/// <summary>
	/// XNodeCollection derived from Dictionary of XNode and XNodeInfo.
	/// </summary>
	public class XNodeCollection {
		private Dictionary<XNode, XNodeInfo> dictionary;

		public XNodeCollection() {
			dictionary = new Dictionary<XNode, XNodeInfo>();
		}

		public Dictionary<XNode, XNodeInfo>.ValueCollection Values {
			get { return dictionary.Values; }
		}

		public void Clear() {
			dictionary.Clear();
		}

		public void Add(XNode key, XNodeInfo value) {
			dictionary.Add(key, value);
		}

		public void Remove(XNode key) {
			dictionary.Remove(key);
		}

		public bool ContainsKey(XNode key) {
			return dictionary.ContainsKey(key);
		}

		public XNodeInfo this[XNode key] {
			get { return dictionary[key]; }
			set { dictionary[key] = value; }
		}

	}
}